package com.zhc.loom.thread;

//import java.util.Random;

/**
 * 多线程死锁
 * 
 * 多线程以及多进程改善了系统资源的利用率并提高了系统 的处理能力。然而，并发执行也带来了新的问题——死锁。所谓死锁是指多个线程因竞争资源而造成的一种僵局（互相等待），若无外力作用，这些进程都将无法向前推进。
 * 下面我们通过一些实例来说明死锁现象。
 * 先看生活中的一个实例，2个人一起吃饭但是只有一双筷子，2人轮流吃（同时拥有2只筷子才能吃）。某一个时候，一个拿了左筷子，一人拿了右筷子，2个人都同时占用一个资源，等待另一个资源，这个时候甲在等待乙吃完并释放它占有的筷子，同理，乙也在等待甲吃完并释放它占有的筷子，这样就陷入了一个死循环，谁也无法继续吃饭。。。
 * 在计算机系统中也存在类似的情况。例如，某计算机系统中只有一台打印机和一台输入 设备，进程P1正占用输入设备，同时又提出使用打印机的请求，但此时打印机正被进程P2 所占用，而P2在未释放打印机之前，又提出请求使用正被P1占用着的输入设备。这样两个进程相互无休止地等待下去，均无法继续执行，此时两个进程陷入死锁状态。
 *
 */
public class LockThreadTest implements Runnable {
	
	public static void main(String[] args) throws Exception {
        //创建Runnable的实现类对象
		LockThreadTest ltt1 = new LockThreadTest();
		ltt1.x = 0;
		LockThreadTest ltt2 = new LockThreadTest();
		ltt2.x = 1;
        //把Runnable实现类对象加入线程中，创建2个线程
        Thread t1 = new Thread(ltt1);
        Thread t2 = new Thread(ltt2);
        t1.start();
        t2.start();
        
        t1.join();
        t2.join();
        
        System.out.println("finished !!!");
        
    }

//	public int x = new Random().nextInt(1);// 用随机数随机获取0、1，来模拟CPU随机分配执行权的行为
	public int x = 0;

	@Override
	public void run() {
		System.out.println(x);
		while (true) {
			if (x % 2 == 0) {
				// 情况一
				// 先执行A再执行B：即A同学先拿了A门的钥匙去开A门，然后打算开B门
				synchronized (Lock.lockA) {
					System.out.println("A同学...开A门");
					try {  
	                    Thread.sleep(5000);  
	                } catch (Exception e) {  
	                    e.printStackTrace();  
	                }
					synchronized (Lock.lockB) {
						System.out.println("A同学...开B门");
					}
				}
			} else {
				// 情况二
				// 先执行B执行A：B同学先拿了B门的钥匙，去开B门，然后打算开A门
				synchronized (Lock.lockB) {
					System.out.println("B同学...开B门");
					try {  
	                    Thread.sleep(5000);  
	                } catch (Exception e) {  
	                    e.printStackTrace();  
	                }
					synchronized (Lock.lockA) {
						System.out.println("B同学...开A门");
					}
				}
			}
			x++;
		}

	}
}

/**
 * 创建锁对象
 * @author zhc2054
 */
class Lock {
	// 这里用private封装，为了不让外面随便造锁，限制只能有A，B锁个一把，这样容易出现死锁
	// 即A同学和B同学想相互串门，可是没人只有一把自己房间的钥匙，而且各自都不愿意先给，于是死锁
	private Lock() {
	}

	public static final Object lockA = new Object();
	public static final Object lockB = new Object();
	// 这里使用static 为了让外界可以通过类名调用成员变量lockA和lockB
	// 因为外面无法创建Lock对象，为了让外面在不创对象的情况下调用，加了static，通过类名加变量名访问
}
